//********************************************************************************************************
// Product Name: MapWindow.dll Alpha
// Description:  The basic module for MapWindow version 6.0
//********************************************************************************************************
// The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); 
// you may not use this file except in compliance with the License. You may obtain a copy of the License at 
// http://www.mozilla.org/MPL/ 
//
// Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF 
// ANY KIND, either expressed or implied. See the License for the specificlanguage governing rights and 
// limitations under the License. 
//
// The Original Code is from MapWindow.dll version 6.0
//
// The Initial Developer of this Original Code is Ted Dunsford. Created 3/8/2008 7:19:53 AM
// 
// Contributor(s): (Open source contributors should list themselves and their modifications here). 
//
//********************************************************************************************************

using System;
using System.IO;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Text;

using MapWindow.Geometries; // Envelope
using MapWindow.Main; // Progress Handler
using MapWindow.DirectX;

using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;


namespace MapWindow.DirectX.Data
{
    

    /// <summary>
    /// Texture
    /// </summary>
    public class MeshModelDX : ModelDX
    {
        


        #region Private Variables

      
        Mesh _mesh; // the internal mesh
        string _filename;

        #endregion

        #region Constructors

        /// <summary>
        /// Creates a new instance of a mesh layer
        /// </summary>
        public MeshModelDX()
        {
         
        }

        /// <summary>
        /// Creates a texture with the specified file.  A Load method will open the existing texture.  A Save method will overwrite it.
        /// </summary>
        /// <param name="filename">The filename to associate with this texture.</param>
        public MeshModelDX(string filename): base(filename)
        {
            _filename = filename;

        }

        /// <summary>
        /// Creates a new instance of a meshModelDX class using an existing 3D mesh
        /// </summary>
        /// <param name="mesh">The mesh to draw</param>
        public MeshModelDX(Mesh mesh)
        {
            _mesh = mesh;
        }
    
       
        #endregion

        #region Methods





        /// <summary>
        /// This is the internal drawing method that follows the standard checks.  Drawing is evoked
        /// through the Draw3D command, but internally implemented in the DrawPart method.  After
        /// the initial checks, the Draw3D method will cycle the part integer from 0 to NumParts -1.
        /// </summary>
        /// <param name="args">A DrawArgsDX class with the device and camera.</param>
        protected override void OnDraw(DrawArgsDX args)
        {
            args.Device.RenderState.Lighting = true;
            
            // Set up texture and material
            base.OnDraw(args);
           
           
            args.Device.RenderState.NormalizeNormals = true;
          
            args.Device.RenderState.ZBufferEnable = true;

         
            _mesh.DrawSubset(args.Part);
            args.Device.RenderState.ZBufferEnable = false;
            args.Device.RenderState.Lighting = false;
        }


        
       

        /// <summary>
        /// Clears directX memory during dispose
        /// </summary>
        /// <param name="disposing">boolean disposing</param>
        protected override void Dispose(bool disposing)
        {
            //if (components != null && disposing)
            //{
            //    components.Dispose();
            //}
            if (_mesh != null) _mesh.Dispose();
           
           
        }

        // This sets up the texture if it hasn't been set up yet.
        /// <summary>
        /// Initializes
        /// </summary>
        public override void Initialize(DrawArgsDX args)
        {
           
            if (_mesh == null)
            {
                Open(_filename, args.Device);

            }
            base.Envelope = CalculateEnvelope();
            base.Initialize(args);
        }


        /// <summary>
        /// Actually loads the data from the specified file into this model
        /// </summary>
        /// <param name="filename">The filename to load</param>
        /// <param name="device"></param>
        public void Open(string filename, Device device)
        {
            ExtendedMaterial[] mtrl;
            if (_mesh != null) _mesh.Dispose();
            if (Textures != null && Textures.Count > 0)
            {
                foreach (Texture t in Textures)
                {
                    t.Dispose();
                }
            }
            Textures = new List<Texture>();
            Materials = new List<Material>();
            TextureFiles = new List<string>();
            _mesh = Mesh.FromFile(filename, MeshFlags.Managed, device, out mtrl);

            if ((mtrl != null) && (mtrl.Length > 0))
            {
                for (int i = 0; i < mtrl.Length; i++)
                {
                    Materials.Add(mtrl[i].Material3D);
                    if ((mtrl[i].TextureFilename != null) && (mtrl[i].TextureFilename != string.Empty))
                    {
                        TextureFiles.Add(mtrl[i].TextureFilename);
                    }
                }
            }
            _mesh.ComputeNormals();
            NumParts = mtrl.Length;

        }

      
     
       
        /// <summary>
        /// This layer doesn't actually support changing the image.  Instead, this simply updates the worldfile,
        /// but only if the style is georeferenced.
        /// </summary>
        public override void Save()
        {
            int[] adjacency = new int[_mesh.NumberFaces * 3];
            _mesh.GenerateAdjacency(0, adjacency);
            ExtendedMaterial[] extMaterials = new ExtendedMaterial[Materials.Count];
            for (int i = 0; i < Materials.Count; i++)
            {
                extMaterials[i].Material3D = Materials[i];
                if (TextureFiles != null && i < TextureFiles.Count)
                {
                    extMaterials[i].TextureFilename = TextureFiles[i];
                }
                
            }
            _mesh.Save(_filename, adjacency, extMaterials, XFileFormat.Text);
        }

        #endregion

        #region Properties

        // Calculates the envelope from the vertex data
        private IEnvelope CalculateEnvelope()
        { 
            IEnvelope env = new Envelope();
            Vector3 min, max;
            GraphicsStream vertexData = _mesh.VertexBuffer.Lock(0, 0, LockFlags.ReadOnly);
            Microsoft.DirectX.Direct3D.Geometry.ComputeBoundingBox(vertexData, _mesh.NumberVertices, _mesh.VertexFormat, out min, out max);
            env.SetExtents((double)min.X, (double)min.Y, (double)min.Z, (double)max.X, (double)max.Y, (double)max.Z);
            return env;
        }


        /// <summary>
        /// Gets the envelope
        /// </summary>
        public override IEnvelope Envelope
        {
            get
            {
                if (base.Envelope == null)
                {
                   
                    if (_mesh != null && IsInitialized)
                    {
                        base.Envelope = CalculateEnvelope();
                        
                    }
                    else
                    {
                        IEnvelope env = new Envelope();
                        env.SetExtents(0, 0, 100, 100);
                        base.Envelope = env;
                    }
                    
                }
                return base.Envelope;
                
            }
            protected set
            {
                base.Envelope = value;
            }
        }


     

 

        


    

        #endregion



       
  







        

    }

}
